package com.woniuxy.sensitive.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniuxy.sensitive.entity.SensitiveWordInit;
import com.woniuxy.sensitive.entity.SensitiveWords;
import com.woniuxy.sensitive.service.BaiduAuditService;
import com.woniuxy.sensitive.service.DBSensitiveWordsService;
import com.woniuxy.sensitive.service.SensitiveWordService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class SensitiveWordServiceImpl implements SensitiveWordService {

    // 依赖SensitiveWordInit，而不是直接依赖sensitiveWordMap
    private final Map<String, Object> sensitiveWordMap;
    private final DBSensitiveWordsService dbService;
    @Autowired
    private BaiduAuditService baiduAuditService;

    @Autowired
    public SensitiveWordServiceImpl(SensitiveWordInit sensitiveWordInit,
                                    DBSensitiveWordsService dbService) {
        this.sensitiveWordMap = sensitiveWordInit.getSensitiveWordMap();
        this.dbService = dbService;
        // 从数据库加载敏感词到内存
        initFromDb();
    }

    // 从数据库加载敏感词
    private void initFromDb() {
        List<String> dbWords = dbService.getAllWords();
        for (String word : dbWords) {
            addSensitiveWordToMap(word);
        }
    }

    @SneakyThrows
    @Override
    public boolean containsSensitiveWord(String text) {
        // 先本地DFA检测
        boolean localResult = !getSensitiveWords(text).isEmpty();
        if (!localResult) {
            // 本地无敏感词时进行百度云二次审核
            return !baiduAuditService.auditText(text);
        }
        return true;
    }

    @Override
    public List<String> getSensitiveWords(String text) {
        List<String> sensitiveWords = new ArrayList<>();
        for (int i = 0; i < text.length(); i++) {
            int length = checkSensitiveWord(text, i);
            if (length > 0) {
                sensitiveWords.add(text.substring(i, i + length));
                i = i + length - 1;
            }
        }

        // 如果本地未检测到，用百度云检测
        if (sensitiveWords.isEmpty()) {
            if (!baiduAuditService.auditText(text)) {
                sensitiveWords.add("***");
            }
        }
        return sensitiveWords;
    }

    @Override
    public String replaceSensitiveWords(String text, char replaceChar) {
        String result = text;
        List<String> sensitiveWords = getSensitiveWords(text);
        for (String word : sensitiveWords) {
            String replaceStr = String.valueOf(replaceChar).repeat(word.length());
            result = result.replaceAll(word, replaceStr);
        }
        return result;
    }

    @Override
    @Transactional
    public synchronized void addSensitiveWord(String word) {
        // 1. 先检查是否已存在
        LambdaQueryWrapper<SensitiveWords> query = new LambdaQueryWrapper<>();
        query.eq(SensitiveWords::getWord, word);
        if (dbService.count(query) > 0) {
            return; // 已存在则不重复添加
        }

        // 2. 保存到数据库
        SensitiveWords entity = new SensitiveWords();
        entity.setWord(word);
        entity.setStatus(1); // 启用状态
        entity.setCreateTime(new Date());
        dbService.save(entity);

        // 3. 更新内存中的敏感词库
        addSensitiveWordToMap(word);
    }

    @Override
    @Transactional
    public synchronized void removeSensitiveWord(String word) {
        // 1. 从数据库删除（逻辑删除或物理删除）
        LambdaQueryWrapper<SensitiveWords> query = new LambdaQueryWrapper<>();
        query.eq(SensitiveWords::getWord, word);
        // 物理删除
        dbService.remove(query);
        // 或逻辑删除：
        // SensitiveWords entity = new SensitiveWords();
        // entity.setStatus(0); // 禁用
        // dbService.update(entity, query);

        // 2. 更新内存中的敏感词库
        removeWord(sensitiveWordMap, word, 0);
    }
    /**
     * 将敏感词添加到内存DFA词库（内部工具方法）
     */
    private void addSensitiveWordToMap(String word) {
        Map<String, Object> nowMap = sensitiveWordMap;
        for (int i = 0; i < word.length(); i++) {
            char keyChar = word.charAt(i);
            String key = String.valueOf(keyChar);
            Object tempMap = nowMap.get(key);

            if (tempMap != null) {
                nowMap = (Map<String, Object>) tempMap;
            } else {
                Map<String, Object> newMap = new ConcurrentHashMap<>();
                newMap.put("isEnd", "0");
                nowMap.put(key, newMap);
                nowMap = newMap;
            }

            if (i == word.length() - 1) {
                nowMap.put("isEnd", "1");
            }
        }
    }
    @SuppressWarnings("unchecked")
    private boolean removeWord(Map<String, Object> currentMap, String word, int index) {
        if (index == word.length()) {
            String isEnd = (String) currentMap.get("isEnd");
            if ("1".equals(isEnd)) {
                currentMap.put("isEnd", "0");
                return currentMap.size() == 1;
            }
            return false;
        }

        char c = word.charAt(index);
        String key = String.valueOf(c);
        Map<String, Object> nextMap = (Map<String, Object>) currentMap.get(key);
        if (nextMap == null) {
            return false;
        }

        boolean shouldRemoveCurrentNode = removeWord(nextMap, word, index + 1) &&
                "0".equals(nextMap.get("isEnd")) &&
                nextMap.size() == 1;

        if (shouldRemoveCurrentNode) {
            currentMap.remove(key);
            return currentMap.size() == 1 && currentMap.containsKey("isEnd");
        }

        return false;
    }

    @SuppressWarnings("unchecked")
    private int checkSensitiveWord(String text, int beginIndex) {
        boolean flag = false;
        int matchFlag = 0;
        Map<String, Object> nowMap = sensitiveWordMap;
        for (int i = beginIndex; i < text.length(); i++) {
            char word = text.charAt(i);
            String key = String.valueOf(word); // 这里新增转换，之前遗漏了！
            nowMap = (Map<String, Object>) nowMap.get(key);
            if (nowMap == null) {
                break;
            }
            matchFlag++;
            if ("1".equals(nowMap.get("isEnd"))) {
                flag = true;
            }
        }
        if (!flag) {
            matchFlag = 0;
        }
        return matchFlag;
    }

    @Override
    public Page<SensitiveWords> listSensitiveWords(int pageNum, int pageSize, String word) {
        LambdaQueryWrapper<SensitiveWords> wrapper = new LambdaQueryWrapper<>();
        if (word != null && !word.isEmpty()) {
            wrapper.like(SensitiveWords::getWord, word);
        }
        return dbService.page(new Page<>(pageNum, pageSize), wrapper);
    }
}